﻿using Autofac;
using Autofac.Extras.DynamicProxy;
using Castle.DynamicProxy;
using SBlogCore.Common.AutofacExtend.Aops;
using SBlogCore.Common.DatabaseAccessor.Repositorys.SQLSuger;
using System.Reflection;
using SBlogCore.Common.DatabaseAccessor.Repositorys.EFCore;

namespace SBlogCore.Common.AutofacExtend.Modules
{
    [SkipScan]
    public class AutofacModuleRegister : Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            BuilderLoad(builder);
        }
        public static void BuilderLoad(ContainerBuilder builder)
        {
            var registerAssemblyNames = AppSetting.ReadAppSettings("RegisterAssembly:Names");
            //要注册的程序集
            var assemblyApplication = LoadAssmbly(registerAssemblyNames.Split(','));
            CreateAutoFac(builder, assemblyApplication, (b) =>
            {
                //注册aop
                builder.RegisterAop<CoreLogAop>(b);
                builder.RegisterAop<SBlogCacheAop>(b);
            });
        }
        /// <summary>
        /// 注册AutoFac
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="assemblysApplication"></param>
        /// <param name="registerAop"></param>
        private static void CreateAutoFac(ContainerBuilder builder, Assembly[] assemblysApplication, Action<List<Type>> registerAop)
        {
            
            var cacheType = new List<Type>();
            //AOP注册
            registerAop(cacheType);
            // 获取 Service.dll 程序集服务，并注册
            builder.RegisterAssemblyTypes(assemblysApplication)
                      .Where(RegisterClassNameEnds)//注册结尾为ServiceS或者Respository的类
                      .AsImplementedInterfaces()//自动的以I开头的为接口返回去掉I的的实例
                      .InstancePerDependency()//每次请求创建新的实例，SingleInstance 单例 InstancePerRequest 
                      .PropertiesAutowired()//允许属性注入
                      .EnableInterfaceInterceptors()//引用Autofac.Extras.DynamicProxy;
                      .InterceptedBy(cacheType.ToArray());//允许将拦截器服务的列表分配给注册。
            //普通注册
            //builder.RegisterType<DapperRepository>().As<IDapperRepository>();
            //注册泛型类
            builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
            builder.RegisterGeneric(typeof(SqlSugerRepository<>)).As(typeof(ISqlSugerRepository<>));
        }
        /// <summary>
        /// 要注册的类的名字结尾
        /// </summary>
        /// <param name="w"></param>
        /// <returns></returns>
        private static bool RegisterClassNameEnds(Type w)
        {
            var registerClassNameGroup = new List<string>();
            var registerClassName = AppSetting.ReadAppSettings("RegisterAssembly:EndWith");
            if (string.IsNullOrEmpty(registerClassName))
            {
                registerClassNameGroup.Add("Service");
            }
            else
            {
                registerClassNameGroup = registerClassName.Split(',').ToList();
            }
            bool? v=null;
            foreach (var classNameEnd in registerClassNameGroup)
            {
                v = v == null ? w.Name.EndsWith(classNameEnd) : v.Value || w.Name.EndsWith(classNameEnd);
            }
            //v = w.Name.EndsWith("Service") || w.Name.EndsWith("Repository");
            return v??false;
        }

        /// <summary>
        /// 加载程序集
        /// </summary>
        /// <param name="assemblynames"></param>
        /// <returns></returns>
        private static Assembly[] LoadAssmbly(params string[] assemblynames)
        {
            var basePath = AppContext.BaseDirectory;
            List<Assembly> assemblyList = new List<Assembly>();
            foreach (var item in assemblynames)
            {
                var applicationDll = Path.Combine(basePath, item);
                var assemblysApplication = Assembly.LoadFrom(applicationDll);
                assemblyList.Add(assemblysApplication);
            }
            return assemblyList.ToArray();
        }

    }
    /// <summary>
    /// Autofac静态类扩展
    /// </summary>
    internal static class AutofacModuleRegisterStatic
    {
        /// <summary>
        /// AOP注册
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="builder"></param>
        /// <param name="cacheType"></param>
        internal static void RegisterAop<T>(this ContainerBuilder builder, List<Type> cacheType) where T : IInterceptor
        {
            builder.RegisterType<T>();
            cacheType.Add(typeof(T));
        }
    }
}
